package com.example.PolimiAssistant;

import android.accounts.Account;
import android.accounts.AccountAuthenticatorActivity;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountManager;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.*;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;
import com.Wsdl2Code.WebServices.PolimiAssistant.PoliUser;
import com.Wsdl2Code.WebServices.PolimiAssistant.UserProfile;
import com.example.PolimiAssistant.common.DialogHandler;
import com.example.PolimiAssistant.utils.*;

/**
 * LoginScreen.java
 *
 * This activity allows the user to use their username and password
 * to retrieve their account information from the *POLIMI* servers,
 * connecting throught web service technologies.
 */
public class LoginScreen extends AccountAuthenticatorActivity{

    /**
     * Declare the context of the application
     */
    private final Context context = this;

    /**
     * The tag used for the logs.
     */
    private final String TAG = context.getClass().getSimpleName();

    /**
     * The user name input by the user.
     */
    private String username;

    /**
     * The password input by the user.
     */
    private String password;

    /**
     * The account manager used to request and add account.
     */
    private AccountManager accountManager;

    /**
     * The user that will hold the data to be sent to the account manager
     */
    private PoliUser poliuser;

    /**
     * The user profile will hold all the relevant data for one user
     */
    private UserProfile userProfile;

    /**
     * Variable that saves the choice from the user to save or not the login
     * data in the device.
     */
    private boolean saveInPhone;

    /**
     * Auxiliary variable for the UI
     */
    private CheckBox checkBox;


    public void onCreate(Bundle savedInstanceState) {

        //0. Initialize main variables
        saveInPhone = false;

        //1. Save the state of the activity
        super.onCreate(savedInstanceState);

        //2. Configure main display options

        //Avoid banding problems with the gradient background
        getWindow().setFormat(PixelFormat.RGBA_8888);

        // Set fixed portrait orientation
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

        // Hide title bar
        requestWindowFeature(Window.FEATURE_NO_TITLE);

        //3. Set the layout used for this activity
        setContentView(R.layout.login_screen);


        //4. Extra configurations

        /*
         * getSupportActionBar().setDisplayHomeAsUpEnabled(true);
         * Cannot be used here due to the configurations in the
         * android manifest.
         */

        //5. Listeners
        addListenerOnCheckStorage();


    }

    /**
     * This method checks if the user agrees to store the username and password in
     * the device, facing all the possible consequences and liberating the app from
     * any responsibility.
     */
    private void addListenerOnCheckStorage() {


        //1. Search for the checkbox
        //final CheckBox checkBox;
        checkBox = (CheckBox) findViewById(R.id.loginscreen_checkstore);

        //2. Create the listener
        checkBox.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

                String dialogMessage;
                String dialogTitle;
                String dialogYes;
                String dialogNo;


                //3. If the box is checked, perform the corresponding actions
                if (((CheckBox) v).isChecked()) {

                    //3.1 Load the acceptance of responsibility strings

                    dialogMessage = getResources().getString(R.string.
                            login_storing_responsibility_message);
                    dialogTitle = getResources().getString(R.string.
                            login_storing_responsibility_title);
                    dialogYes = getResources().getString(R.string.
                            login_storing_responsibility_yes);
                    dialogNo = getResources().getString(R.string.
                            login_storing_responsibility_no);

                    //2. Build and display the dialog
                    DialogHandler dialog;
                    dialog = new DialogHandler();
                    dialog.confirmDialog((Activity)context, dialogTitle, dialogMessage,
                            dialogYes, dialogNo, ifAccept(), ifDeny());

                } else {
                    //No message displayed
                }
            }
        });
    }

    /**
     * This method is attached to the previous one in the sense that this is the action
     * performed when the message invoked by the previous method is accepted
     * @return
     */
    private Runnable ifAccept(){

        return new Runnable() {

            @Override
            public void run() {
                saveInPhone = true;
            }
        };

    }

    /**
     * This method is attached to the previous one in the sense that this is the action
     * performed when the message invoked by the previous method is denied
     * @return
     */
    private Runnable ifDeny(){

        return new Runnable() {

            @Override
            public void run() {
                checkBox.setChecked(false);
            }
        };
    }



    /**
     * Login class that process the login information, login settings and
     * calls the correct classes to handle this.
     *
     * Todo: correct the algorithm numbers
     */
    public void login(View view){

        //1. Obtain the password and username to make the login

        EditText usernameEditText;
        usernameEditText = (EditText)findViewById(R.id.loginscreen_input_username);
        EditText passwordEditText;
        passwordEditText = (EditText)findViewById(R.id.loginscreen_input_password);


        username = usernameEditText.getText().toString();
        password = passwordEditText.getText().toString();

        Log.i(TAG, "The username is: "+username+" and the password is: "+password);


        //2. Test the validity of the credentials, client side

        //2.1 Check that the user name isnt empty
        if (username == null || username.equalsIgnoreCase("")) {

            Toast.makeText(context, getResources().getString(R.string.warning_username_empty),
                    Toast.LENGTH_LONG).show();
            return;
        }

        //2.2 Check that the password isnt empty
        if (password == null || password.equalsIgnoreCase("")) {
            Toast.makeText(context, getResources().getString(R.string.warning_password_empty),
                    Toast.LENGTH_LONG).show();
            return;
        }

        //3 Execute the server side check and login

         /*
          * This method instantiate an asynchronious task and execute it
          * at the same time.
          */
            new AsyncCaller().execute();
    }

    /**
     * This method is an asynchronous method that uses the Android asynchronous task
     * framework in order to check the validity of the user credentials on the server
     * and save that information in the account manager in the device.
     */
    private class AsyncCaller extends AsyncTask<Void, Void, PoliUser>
    {

        //1. Create the loading dialog
        ProgressDialog loadingDialog;
        {
            loadingDialog = new ProgressDialog(LoginScreen.this);
        }

        @Override
        protected void onPreExecute() {

            super.onPreExecute();

            //2. Set the message and show the dialog
            loadingDialog.setMessage("Loading...");
            loadingDialog.show();
        }

        @Override
        protected PoliUser doInBackground(Void... params) {

            Log.i(TAG, "Calling the web service to obtain the user data..");

            //3. Declare the account data manager
            UserDataManager userDataManager;
            userDataManager = new UserDataManager();

            //4. Obtain the user profile info throught the login method
            PoliUser poliUser;
            poliUser = userDataManager.login(username,password);

            //5. Get the user data ahead of time
            if(poliUser != null){
                userProfile = userDataManager.getUserProfile(poliUser.auth_token);
            }

            return poliUser;
        }

        @Override
        protected void onPostExecute(PoliUser poliUser) {

            super.onPostExecute(poliUser);

            Log.i(TAG, "Response, Token : " + poliUser.auth_token+" , Name: "
                    + poliUser.name);


            //5. Manage the user data

            //String oAuthToken;
            //oAuthToken = poliuser.auth_token;
            //String oAuthToken = "GetAuthToken(params...)";

            //If the server give us an authorization token correctly
            if(poliUser != null){

                //If the data must be saved in the phone
                if(saveInPhone){

                    //5.1 Call the create account method
                    createAccount(poliUser.person_code,
                            poliUser.password, poliUser.auth_token);

                }else{

                    //5.1 Call the not create account method
                    dontCreateAccount(poliUser.auth_token);
                }

            }else{

                //Error in login data
                Toast.makeText(context, R.string.error_invalid_credentials,
                        Toast.LENGTH_LONG).show();
            }

            //6. Hide the loading dialog
            loadingDialog.dismiss();
        }

    }

    /**
     * This method creates an account using the account manager. It verifies
     * if the user has an account and where is it comming from (splash screen or
     * account settings)
     * @param username
     * @param password
     * @param oAuthToken authorization token given by the Polimi server
     */
    private void createAccount(String username, String password, String oAuthToken){

        //1. Check if an account already exist
        boolean existAccount = false;
        existAccount = AccountDataManager.isThereAnAccount(context);

        if(existAccount){

            /*
             * This case will always come from the system
             * settings -> add account
             */

            Log.i(TAG,"Account already exist..");

            //2. Warn the user that the account already exist
            Toast.makeText(context, R.string.warning_account_already_exist,
                    Toast.LENGTH_LONG).show();

            //3. Create intent and redirect it to the main menu
            Intent goToMainMenu = new Intent(context, MainMenu.class);
            startActivity(goToMainMenu);

            //4. Finish this activity
            finish();

        }else{

            //2. Create new account
            boolean accountCreated = false;
            accountCreated = AccountDataManager.createAccount(context,
                    username, password, oAuthToken);

            //If the account was created successfully
            if(accountCreated){

                /*
                 * The data is saved in the preferences in order to make the auth
                 * for the online data retrieval easier. On future work, offline
                 * retrieval doesnt need to save the token in the preferences.
                 */

                //4. Insert into the preferences the user username and autho key and the profile
                //3. Instantiate the preference manager and set the user option into yes
                PreferencesManager preferences;
                preferences = new PreferencesManager(context);
                preferences.setUserName(username);
                preferences.setToken(oAuthToken);

                Log.i(TAG,"Account registered and data saved in the preferences");

                //4. Filter if the intent is coming from the splash screen
                Intent incomingIntent;
                incomingIntent = getIntent();

                String comingFrom;
                comingFrom = incomingIntent.getStringExtra("COMING_FROM");

                Toast.makeText(context, R.string.info_add_account_successful,
                        Toast.LENGTH_LONG).show();


                //If its coming from the splash screen(default case)
                if(comingFrom != null &&
                        comingFrom.equals(SplashScreen.class.getSimpleName())){

                    //5. Sync the information to the DB
                    //TODO: sync();

                    //6. Redirect the activity to the main menu
                    Intent goToMainMenu;
                    goToMainMenu = new Intent(context, MainMenu.class);
                    goToMainMenu.putExtra("COMING_FROM", context.getClass().getSimpleName());

                    startActivity(goToMainMenu);

                }else{

                    //5. Finish the activity comming from the auth android serv.
                    finish();
                }

            }else{
                Toast.makeText(context,R.string.error_creating_account,Toast.LENGTH_SHORT);
            }
        }
    }

    /**
     * This method routes the user to the main menu given that the user
     * dont want to create an account. Verifies if the user has an account
     *
     * @param oAuthToken authorization token given by the Polimi server
     */
    private void dontCreateAccount(String oAuthToken){

        //1. Check if an account already exist
        boolean existAccount;
        existAccount = AccountDataManager.isThereAnAccount(context);

        //2.Create the intent to go to the main menu
        Intent goToMainMenu;
        goToMainMenu = new Intent(context, MainMenu.class);

        if(existAccount){

            /*
             * This case will happen unlikely coming from the splash
             * screen given that from there, this verification is done.
             * But because the login screen is also used by the android
             * account service it may come from there.
             */

            Log.i(TAG,"Account already exist..");

            Toast.makeText(context, R.string.warning_account_already_exist,
                    Toast.LENGTH_LONG).show();

            //3. Start the new activity
            startActivity(goToMainMenu);

            //4. Finish the login activity
            finish();

        }else{

            Toast.makeText(context, R.string.warning_data_notsaved,
                    Toast.LENGTH_LONG).show();

            //3. Instantiate the preference manager and set the user option into yes
            PreferencesManager preferences;
            preferences = new PreferencesManager(context);
            preferences.setToken(oAuthToken);

            Log.i(TAG,"Minimum data saved in the preferences");

            //4. Start the new activity
            startActivity(goToMainMenu);

            //5. Finish the login activity
            finish();
        }
    }
}